package com.ruoyi.common.wx.service;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.http.HttpClientUtil;
import com.ruoyi.common.http.HttpUtils;
import com.ruoyi.common.redis.RedisLock;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class IWxService {

    @Value("${wechat.properties.appid}")
    private String appid;

    @Value("${wechat.properties.secret}")
    private String secret;

    public static final String WX_CODE_2_SESSION = "https://api.weixin.qq.com/sns/jscode2session";
    public static final String WX_GET_PHONE_NUMBER = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";

    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    RedisLock redisLock;
    @Autowired
    IWxUserService wxUserService;

    public String getLink(String path, String query){
        String accesstoken = getAccesstokenSyn();
        System.out.println(accesstoken);

        String res = HttpClientUtil.doPost("https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + accesstoken, new JSONObject(){{
            put("path", path);
            put("query", query);
        }});

        JSONObject jsonObject = JSONObject.parseObject(res);
        if(jsonObject.containsKey("errcode") && "0".equals(jsonObject.getString("errcode"))){
            return jsonObject.getString("url_link");
        }
        return null;
    }

    /**
     * 获取accessToken
     * @return
     */
    public String getAccesstokenSyn() {
        Object accesstoken = redisTemplate.opsForValue().get(appid + "_accesstoken");
        if(accesstoken != null){
            return accesstoken.toString();
        } else {
            try{
                /**
                 * 尝试 加锁
                 */
                int count = 0;
                while (true){
                    if(redisLock.tryLock("query_accesstoken", 5)) break;
                    Thread.sleep(10);
                    if(count > 300) return null;
                    count ++ ;
                }
                accesstoken = redisTemplate.opsForValue().get(appid+"_accesstoken");
                if(accesstoken != null){
                    return accesstoken.toString();
                } else {
                    String res = HttpClientUtil.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret);
                    if(res.contains("errcode")) throw new Exception(res);
                    String accessToken = JSONObject.parseObject(res).getString("access_token");
                    //accesstoken 存入redis
                    redisTemplate.opsForValue().set(appid+"_accesstoken", accessToken);
                    redisTemplate.expire(appid+"_accesstoken", 20*60, TimeUnit.SECONDS);

                    return accessToken;
                }
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                redisLock.unlock("query_accesstoken");
            }
        }
        return null;
    }

    /**
     * 获取 session_key
     */
    public String getSessionKey(String jsCode) throws IOException {
        Map<String, String> map = new HashMap<>(4);
        map.put("appid", appid);
        map.put("secret", secret);
        map.put("js_code", jsCode);
        map.put("grant_type", "authorization_code");
        return HttpClientUtil.get(WX_CODE_2_SESSION, map);
    }

    public JSONObject getWxInfo(String jsCode) throws IOException {

        JSONObject sessionKeyJson = JSONObject.parseObject(getSessionKey(jsCode));

        if(sessionKeyJson.containsKey("session_key") && StringUtils.isNotEmpty(sessionKeyJson.getString("session_key"))){

            JSONObject json = new JSONObject();
            json.put("openid", sessionKeyJson.getString("openid"));
            /** 获取token */
            json.put("token", wxUserService.checkEmpower(sessionKeyJson.getString("openid")));
            return json;
        } else {
            throw new RuntimeException("session_key获取失败！");
        }
    }

    /**
     * 获取手机号码
     * @param code
     * @return
     */
    public String getUserPhonenumber(String code) throws IOException {

        Assert.hasLength(code, "请授权！");

        /** 设置body */
        Map<String, String> map = new HashMap<>(1);
        map.put("code", code);

        String body = "{\"code\": \""+code+"\"}";
        JSONObject json = JSONObject.parseObject(HttpUtils.post(WX_GET_PHONE_NUMBER + "?access_token=" + getAccesstokenSyn(),
                RequestBody.create(body, MediaType.get("application/json"))));

        if(json.containsKey("errcode") && "0".equals(json.getString("errcode"))){
            return json.getJSONObject("phone_info").getString("phoneNumber");
        }
        throw new RuntimeException("授权失败！");
    }

}
